﻿using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;

using Centido.Core;

namespace Centido.Management.ConsoleManager
{
    /// <summary>
    ///   A console command that revokes the specified table permission
    /// from the specified principal.
    /// </summary>
    internal class RevokeCommand : PermissionCommandBase
    {
        /// <summary>
        ///   The table name parameter.
        /// </summary>
        public const string TableNameParameter = "table";

        /// <summary>
        ///   The table name parameter (short name).
        /// </summary>
        public const string TableNameShortParameter = "t";

        /// <summary>
        ///   The principal name parameter.
        /// </summary>
        public const string PrincipalNameParameter = "principal";

        /// <summary>
        ///   The principal name parameter (short name)
        /// </summary>
        public const string PrincipalNameShortParameter = "p";

        /// <summary>
        ///   The data action parameter.
        /// </summary>
        public const string DataActionParameter = "action";

        /// <summary>
        ///   The data action parameter (short name).
        /// </summary>
        public const string DataActionShortParameter = "a";


        /// <summary>
        ///   Gets the console command name.
        /// </summary>
        public override string Name
        {
            get { return "revoke"; }
        }


        /// <summary>
        ///   Gets the console command description.
        /// </summary>
        public override string Description
        {
            get { return Messages.RevokeCommandDescription; }
        }


        /// <summary>
        ///   Gets the console command full description.
        /// </summary>
        public override string FullDescription
        {
            get { return Messages.RevokeCommandFullDescription; }
        }


        /// <summary>
        ///   Executes the console command.
        /// </summary>
        /// <param name="context">The console command execution context.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="context"/> is null.</exception>
        public override void Execute(CommandExecutionContext context)
        {
            base.Execute(context);

            var domain = context.CurrentDomain;

            if (domain == null) return;

            // If the current user has no permission to perform the action
            if (!domain.CurrentUser.CanChangeSecurity)
            {
                Console.WriteLine(Messages.NeedCanChangeSecurityPermissionMessage);
                return;
            }

            // The target tables
            var tableList = new List<Table>();

            // If the table parameter was specified
            if (context.ParameterValueIsNotEmpty(TableNameParameter, TableNameShortParameter))
            {
                // The table name
                var tableName = context.GetParameterValue(TableNameParameter, TableNameShortParameter);

                // Trying to find the table with the specified name
                var table = domain.GetTable(tableName);

                // If there is no table with the specified name
                if (table == null)
                {
                    Console.WriteLine(Messages.CannotFindTableError, tableName);
                    return;
                }

                tableList.Add(table);
            }
            // If the table name parameter was specified
            else
                // ... then adding all tables to the target list
                tableList.AddRange(domain.Tables);

            // The target security principal
            IPrincipal targetPrincipal = domain.CurrentUser;

            // If the principal name was specified
            if (context.ParameterValueIsNotEmpty(PrincipalNameParameter, PrincipalNameShortParameter))
            {
                // The principal name
                var principalName = context.GetParameterValue(PrincipalNameParameter, PrincipalNameShortParameter);

                // Trying to find a principal with the specified name
                var principal = domain.GetPrincipal(principalName);

                // If there is no principal with the specified name
                if (principal == null)
                {
                    Console.WriteLine(Messages.CannotFindPrincipalError, principalName);
                    return;
                }

                targetPrincipal = principal;
            }

            // The target data actions
            var targetActions = new List<DataAction>();

            // If the data action parameter was specified
            if (context.ParameterValueIsNotEmpty(DataActionParameter, DataActionShortParameter))
            {
                var dataAction = GetDataAction(context.GetParameterValue(DataActionParameter, DataActionShortParameter));

                // If the data action was recognized
                if (dataAction != null)
                    targetActions.Add(dataAction.Value);
                else
                {
                    Console.WriteLine(Messages.DataActionWrongValueError);
                    return;
                }
            }
            // If the data action parameter was not specified
            else
            {
                targetActions.Add(DataAction.Select);
                targetActions.Add(DataAction.Insert);
                targetActions.Add(DataAction.Update);
                targetActions.Add(DataAction.Delete);
            }

            try
            {
                foreach (var table in tableList)
                    foreach (var dataAction in targetActions)
                    {
                        // Searching for any previous permissions for the principal and the data action
                        var previousPermission = table.Permissions.FirstOrDefault(p =>
                            p.Principal.Name == targetPrincipal.Name
                            && p.DataAction == dataAction);

                        // If there was such a permission
                        if (previousPermission != null)
                            previousPermission.Delete();
                    }
            }
            catch (DbException e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine();
                return;
            }

            // Displaying the success message
            Console.WriteLine(Messages.CommandCompletedMessage);
        }
    }
}
